/**
 * 工具类相关封装函数
 */

/**
 * 字节单位转换
 * @param {Number} bytes 字节数
 * @returns xxKB xxMB xxGB xxTB
 */
export function formatBytes(bytes) {
    let units = ["B", "KB", "MB", "GB", "TB"];
    let index = 0;
    let num = parseInt(bytes);
    // 如果字节数大于等于1024，并且单位索引小于数组长度，就继续循环
    while (num >= 1024 && index < units.length) {
        num = num / 1024;
        index++;
    }
    // 返回格式化后的字符串，保留一位小数，并加上对应的单位
    return num.toFixed(1) + " " + units[index];
}

/**
 * 上传文件
 * @param {String} method 请求方法
 * @param {String} url 请求地址
 * @param {File} file 文件
 * @param {Function} onUpload 上传进度回调
 * @param {Function} onDownload 下载进度回调
 * @param {Function} onFinish 上传完成回调
 * @param {Function} onError 上传错误回调
 */
export function upload(method, url, file, onUpload, onDownload, onFinish, onError) {
    let xhr = new XMLHttpRequest();
    // 上传进度
    xhr.upload.onprogress = function (e) {
        let percent = Math.floor((e.loaded / e.total) * 100);
        onUpload(percent);
    }
    xhr.onprogress = function (e) {
        let percent = Math.floor((e.loaded / e.total) * 100);
        onDownload(percent);
    }
    // 请求完成
    xhr.onload = function () {
        if (this.status != 200) {
            onError(this.status);
        } else {
            let res = JSON.parse(this.responseText);
            onFinish(res);
        }
    }
    // 请求报错
    xhr.onerror = function () {
        onError(this.status);
    }

    xhr.open(method, url);
    xhr.setRequestHeader('Accept', 'application/json, text/plain, */*')

    let form = new FormData()
    form.append('image', file)
    xhr.send(form);

    return xhr;
}

/**
 * 封装元素选择器, 包含show(),hide()两个方法
 * @param {String} selector 选择器
 * @returns {Element}
 * @example $('#id').show().hide()
 */
export default function $(selector) {
    if (!selector) return null;

    var elements = document.querySelectorAll(selector);
    if (elements.length === 0) {
        console.warn(`未找到元素 ${selector}`);
        return null;
    }

    // 包装对象，用于扩展元素的功能
    function ElementWrapper(element) {
        this.element = element;
    }

    // 处理show hide功能
    const handler = function () {
        this.element.classList.toggle("hide");
        return this; // 链式调用
    };

    // 给包装对象添加 show 和 hide 方法
    ElementWrapper.prototype.show = handler

    ElementWrapper.prototype.hide = handler

    /**
     * 移除指定元素
     * @param {*} selector
     */
    ElementWrapper.prototype.remove = function (selector) {
        let nodeList = this.element.querySelectorAll(selector);

        nodeList.forEach(function (node) {
            node.parentNode.removeChild(node);
        });
    }

    // 根据查询结果返回包装对象或包装对象数组
    if (elements.length === 1) {
        // 如果只找到一个元素，返回该元素的包装对象
        return new ElementWrapper(elements[0]);
    } else {
        // 如果找到多个元素，返回包装对象的数组
        return Array.from(elements).map(function (element) {
            return new ElementWrapper(element);
        });
    }
}

/**
 * 滚动到此元素的位置
 * @param {*} selector 元素选择器
 */
export function scrollView(selector) {
    var element = document.querySelector(selector);
    var position = element.offsetTop;

    window.scrollTo({
        top: position,
        left: 0,
        behavior: "smooth",
    });
}

/**
 *  输出可见区域的宽高(例如父元素有滚动条，子元素在展示区域内的部分)
 * @param {Element} childElement 子元素
 * @param {Element} parentElement 父元素
 * @returns {Object}
 */
export function getVisibleAreaInParent(childElement, parentElement) {
    // 获取子元素的边界信息
    const childRect = childElement.getBoundingClientRect();

    // 获取父元素的边界信息和滚动偏移量
    const parentRect = parentElement.getBoundingClientRect();
    const parentScrollLeft = parentElement.scrollLeft;
    const parentScrollTop = parentElement.scrollTop;

    // 计算子元素在父元素中的可见区域
    const visibleLeft = Math.max(childRect.left - parentRect.left + parentScrollLeft, 0);
    const visibleTop = Math.max(childRect.top - parentRect.top + parentScrollTop, 0);
    const visibleRight = Math.min(childRect.right - parentRect.left + parentScrollLeft, parentRect.width);
    const visibleBottom = Math.min(childRect.bottom - parentRect.top + parentScrollTop, parentRect.height);

    // 返回可见区域的尺寸和位置
    return {
        left: visibleLeft,
        top: visibleTop,
        width: visibleRight - visibleLeft,
        height: visibleBottom - visibleTop
    };
}

/**
* 相交判断
* @param {Element} element1
* @param {Element} element2
* @returns {boolean}
*/
export function checkOverlap(element1, element2) {
    const rect1 = element1.getBoundingClientRect();
    const rect2 = element2.getBoundingClientRect();

    // 检查两个矩形是否相交
    return !(
        rect1.right < rect2.left ||
        rect1.left > rect2.right ||
        rect1.bottom < rect2.top ||
        rect1.top > rect2.bottom
    );
}
